package com.hanxiaozhang;

import com.hanxiaozhang.mysql.MysqlDistributedLock;
import com.hanxiaozhang.redis.RedisClientSingleton;
import com.hanxiaozhang.redis.RedisDistributedLock;
import com.hanxiaozhang.zookeeper.ZkClearInvalidNodeThread;
import com.hanxiaozhang.zookeeper.ZkClientSingleton;
import com.hanxiaozhang.zookeeper.ZkDistributedLock;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;
import org.redisson.api.RedissonClient;

import javax.sql.DataSource;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 功能描述: <br>
 * 〈分布式锁工厂〉
 *
 * @Author:hanxinghua
 * @Date: 2022/8/24
 */
@Slf4j
public class DistributedLockFactory {

    private static AtomicBoolean zkClearInvalidNodeStart = new AtomicBoolean(false);

    private Configuration config;

    public DistributedLockFactory(Configuration config) {
        this.config = config;
    }


    /**
     * 获取分布式锁配置信息
     *
     * @return
     */
    public Configuration getDistributedLockConfig() {
        return config;
    }

    /**
     * 获取zk锁实例
     *
     * @param lockKey
     * @return
     */
    public DistributedLock getZkLock(String lockKey) {

        CuratorFramework client = ZkClientSingleton.getInstance(config);
        initClearInvalidNodeThread(client);
        return new ZkDistributedLock(lockKey, client, config);
    }


    /**
     * 获取zk锁实例
     *
     * @param baseLockPath
     * @param lockKey
     * @return
     */
    public DistributedLock getZkLock(String baseLockPath, String lockKey) {

        CuratorFramework client = ZkClientSingleton.getInstance(config);
        initClearInvalidNodeThread(client);
        return new ZkDistributedLock(baseLockPath, lockKey, client, config);
    }


    /**
     * 获取zk锁实例
     *
     * @param baseLockPath
     * @param lockKey
     * @param client
     * @return
     */
    public DistributedLock getZkLock(String baseLockPath, String lockKey, CuratorFramework client) {

        return new ZkDistributedLock(baseLockPath, lockKey, client);
    }

    /**
     * 获取Redis锁实例
     *
     * @param lockKey
     * @return
     */
    public DistributedLock getRedisLock(String lockKey) {

        RedissonClient client = RedisClientSingleton.getInstance(config);
        return new RedisDistributedLock(lockKey, client);
    }


    /**
     * 获取Redis锁实例
     *
     * @param lockKey
     * @param client
     * @return
     */
    public DistributedLock getRedisLock(String lockKey, RedissonClient client) {

        return new RedisDistributedLock(lockKey, client);
    }

    /**
     * 获取MySQL锁实例
     *
     * @param lockKey
     * @param dataSource
     * @return
     */
    public DistributedLock getMysqlLock(String lockKey, DataSource dataSource) {

        return new MysqlDistributedLock(lockKey, dataSource);
    }


    /**
     * 启动后台清理线程
     *
     * @param client
     */
    private void initClearInvalidNodeThread(CuratorFramework client) {
        if (config.getZkClearInvalidNode() && !zkClearInvalidNodeStart.get()) {
            synchronized (this) {
                if (config.getZkClearInvalidNode() && !zkClearInvalidNodeStart.get()) {
                    ZkClearInvalidNodeThread thread = new ZkClearInvalidNodeThread(client, config);
                    thread.start();
                }
            }
        }
    }

}
